/**
 *  Copyright (C) 2008 Richard Hall
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the 
 *  GNU General Public License as published by the Free Software Foundation; either version 3 of the 
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *  See the GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along with this program; if not, 
 *  see <http://www.gnu.org/licenses>.
 *
 *  Additional permission under GNU GPL version 3 section 7
 *
 *  If you modify this Program, or any covered work, by linking or combining it with [name of library] 
 *  (or a modified version of that library), containing parts covered by the terms of 
 *  [name of library's license], the licensors of this Program grant you additional permission to 
 *  convey the resulting work. {Corresponding Source for a non-source form of such a combination shall 
 *  include the source code for the parts of [name of library] used as well as that of the 
 *  covered work.}
 *
 * 
 */

package com.gpsmedia.control;

import com.google.gdata.util.AuthenticationException;
import com.gpsmedia.utils.FileCheck;
import com.gpsmedia.utils.NmeaDataCollector;
import com.gpsmedia.uploadutils.BlipTvTools;
import com.gpsmedia.uploadutils.PicasaTools;
import com.gpsmedia.dataobject.NmeaData;
import com.gpsmedia.kml.KMLWriter;
import com.gpsmedia.gui.frames.MainFrame;
import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This is the central controlling class. It receives all of the required
 * parameters and farms the work out to the other supporting classes. In theory,
 * it should be possible to make limited use of this API by making use of only
 * this class. Basically, start here......
 * 
 * @author Richard Hall
 */
public class GPS2Google {

    private String inputfile;
    private String outputfile;
    private String picFolder;
    private String audioFolder;
    private Calendar picRealTime;
    private Calendar audioRealTime;
    private TimeZone outputTimeZone;
    private String googleUserName;
    private String bliptvUserName;
    private String googlePassword;
    private String bliptvPassword;
    private double DOPValue;
    private boolean includeAlt;
    private String kmlTitle;
    private FileCheck fc;
    private LinkedHashMap filedata;
    private NmeaDataCollector ndc;
    private KMLWriter kml;
    private PicasaTools pt;
    private BlipTvTools bt;

    
    /**
	 * This method sets the parameters for this object. This is not done using a
	 * constructor so that the object can be instantiated without knowledge of
	 * the parameters.
	 * 
	 * @param inputfilevalue
	 *            The name of the gps log file.
	 * @param outputfilevalue
	 *            The name of the output file (KML file).
	 * @param picFolder
	 *            The name of the folder containing the pictures.
	 * @param audioFolder
	 *            The name of the folder containing the audio.
	 * @param picRealTime
	 *            The time of the first picture acchording to the gps device
	 *            (UTC)
	 * @param audioRealTime
	 *            The time of the first audio acchording to the gps device (UTC)
	 * @param outputTimeZone
	 *            The time zone of the location being recorded.
	 * @param googleUserName
	 *            The google user's login name.
	 * @param googlePassword
	 *            The google user's password.
	 * @param bliptvUserName
	 *            The bliptv user's login name.
	 * @param bliptvPassword
	 *            The bliptv user's password.
	 * @param DOPValue
	 *            The DOP value to test accuracy of gps data.
	 * @param includeAlt
	 *            Whether to include altitude data or not.
	 * @param kmlTitle
	 *            The title of the KML file
	 */
    public void setparams(String inputfilevalue, String outputfilevalue,
            String picFolder, String audioFolder, Calendar picRealTime,
            Calendar audioRealTime, TimeZone outputTimeZone, String googleUserName,
            char[] googlePassword, String bliptvUserName, char[] bliptvPassword, double DOPValue, boolean includeAlt, String kmlTitle) {
        pt = null;
        bt = null;
        kml = null;
        inputfile = inputfilevalue;
        outputfile = outputfilevalue;
        this.picFolder = picFolder;
        this.audioFolder = audioFolder;
        this.picRealTime = picRealTime;
        this.audioRealTime = audioRealTime;
        this.outputTimeZone = outputTimeZone;
        this.bliptvPassword = String.copyValueOf(bliptvPassword);
        this.bliptvUserName = bliptvUserName;
        this.googlePassword = String.copyValueOf(googlePassword);
        this.googleUserName = googleUserName;
        this.DOPValue = DOPValue;
        this.includeAlt = includeAlt;
        this.kmlTitle = kmlTitle;
    }

    /**
	 * This method starts the process of reading the data from the gps log file.
	 * 
	 * @throws Exception
	 */
    public void readdata() throws Exception {


        ndc = new NmeaDataCollector(inputfile, DOPValue, includeAlt);
        ndc.readdata();

        filedata = ndc.getData();
        fc = new FileCheck(filedata, picFolder, audioFolder, picRealTime,
                audioRealTime, outputTimeZone);

        if (picFolder.compareToIgnoreCase("") != 0) {
            fc.tagPicture();
        }

        if (audioFolder.compareToIgnoreCase("") != 0) {

            fc.tagAudio();
        }
        fc.correctTimeValue();
        filedata = fc.getMap();





    }

    /** Select which pictures to include 
     * 
     * @param showFrame Whether to show the frame and select each picture or not show and
     * select all.
     * 
     * @param frame Included as a work around to a problem with the user having access to the MainFrame
     * while selecting Pictures. Will be addressed in the future. If not needed just place null here.
     */
    public void selectPics(boolean showFrame, MainFrame frame) {
        
        fc.setPictureDetails(showFrame, frame);
        
    }

    /** Select which pieces of audio to include 
     *
     * @param showFrame Whether to show the frame and select each audio file or not show and
     * select all.
     * @param frame Included as a work around to a problem with the user having access to the MainFrame
     * while selecting Audio. Will be addressed in the future. If not needed just place null here.
     */
    public void selectAudio(boolean showFrame, MainFrame frame) {
        
        fc.setAudioDetails(showFrame, frame);
        
    }

    /** Send the media to either Google or Bliptv or both. */
    public void sendData() {

        
        if (googleUserName.compareToIgnoreCase("") != 0) {
            try {
                pt = new PicasaTools(googleUserName, googlePassword);

                pt.addAlbum(kmlTitle, "");

            } catch (AuthenticationException ex) {
                Logger.getLogger(GPS2Google.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

        if (bliptvUserName.compareToIgnoreCase("") != 0) {
            try {
                bt = new BlipTvTools(bliptvUserName, bliptvPassword);
            } catch (Exception ex) {
                Logger.getLogger(GPS2Google.class.getName()).log(Level.SEVERE, null, ex);

            }

        }



        Collection col = filedata.values();
        Iterator it = col.iterator();

        while (it.hasNext()) {
            NmeaData datarow = (NmeaData) it.next();

            if (googleUserName.compareToIgnoreCase("") != 0) {
                for (int r = 0; r < 10; r++) {
                    if (datarow.getPictures()[r].isInclude() == true) {
                        pt.addPhoto(datarow.getPictures()[r].getPath(), datarow.getPictures()[r].getTitle(), datarow.getPictures()[r].getDescription(), datarow.getLongdec(), datarow.getLatdec(), datarow.getDate().getTime());
                        datarow.getPictures()[r].setUploadPath(pt.getNewPath());
                    }
                }
            }

            if (bliptvUserName.compareToIgnoreCase("") != 0) {


                if (datarow.getAudio().isInclude() == true) {
                    bt.doUpload(new File(datarow.getAudio().getPath()), datarow.getAudio().getTitle(), datarow.getAudio().getDescription());
                    datarow.getAudio().setAudioUploadPath(bt.getFileURL());
                }
            }

        }






    }

    /**
	 * Starts the process of writing the data to the output KML file.
	 * 
	 * @throws Exception
	 */
    public void writedata() throws Exception {
        
        try {


            if (includeAlt) {
                kml = new KMLWriter(outputfile, "absolute");

            } else {
                kml = new KMLWriter(outputfile, "clampToGround");

            }


            //needed for date comparisons
            SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");

            kml.writeHeader(kmlTitle);
            kml.writeStartStyle();
            kml.writeEndStyle();
            kml.writeAudioStyle();
            kml.writeCameraStyle();
            kml.writeLineStyle();


            Collection col = filedata.values();
            Iterator it = col.iterator();
            NmeaData datarow = null;
            //stops the whole process if there is no data
            if (it.hasNext()) {
                datarow = (NmeaData) it.next();



                kml.writeStartEndFolder(true, formatter.format(datarow.getDate().getTime()), datarow.getLongdeg() + " " + datarow.getLongmins() + datarow.getLongdir(),
                        datarow.getLatdeg() + " " + datarow.getLatmins() + datarow.getLatdir(), String.valueOf(datarow.getLongdec()),
                        String.valueOf(datarow.getLatdec()), datarow.getAltitude());
                kml.writeFolderHeader("Pictures");

                col = filedata.values();
                it = col.iterator();


                while (it.hasNext()) {
                    datarow = (NmeaData) it.next();
                    for (int r = 0; r < 10; r++) {
                        if (datarow.getPictures()[r].isInclude() == true) {

                            //set picture path to uploadpath if file has been uploaded
                            if (datarow.getPictures()[r].getUploadPath().compareToIgnoreCase("") != 0) {
                                datarow.getPictures()[r].setPath(datarow.getPictures()[r].getUploadPath());
                            }


                            // add pictures here
                            kml.addMedia(true, datarow.getPictures()[r].getTitle(),
                                    datarow.getPictures()[r].getPath(), formatter.format(datarow.getDate().getTime()),
                                    datarow.getLongdeg() + " " + datarow.getLongmins() + datarow.getLongdir(),
                                    datarow.getLatdeg() + " " + datarow.getLatmins() + datarow.getLatdir(),
                                    datarow.getPictures()[r].getDescription(),
                                    String.valueOf(datarow.getLongdec()),
                                    String.valueOf(datarow.getLatdec()), datarow.getAltitude(),
                                    datarow.getPictures()[r].getUploadPath().compareToIgnoreCase("") != 0);
                        }
                    }
                }





                kml.writeFolderClose();
                kml.writeFolderHeader("Audio");
                int countAudio = 0;
                col = filedata.values();
                it = col.iterator();

                while (it.hasNext()) {
                    datarow = (NmeaData) it.next();
                    if (datarow.getAudio().isInclude() == true) {


                        //set audio path to uploadpath if it has been uploaded
                        if (datarow.getAudio().getAudioUploadPath().compareToIgnoreCase("") != 0) {
                            datarow.getAudio().setPath(datarow.getAudio().getAudioUploadPath());
                        }

                        //add audio
                        kml.addMedia(false, datarow.getAudio().getTitle(),
                                datarow.getAudio().getPath(), formatter.format(datarow.getDate().getTime()),
                                datarow.getLongdeg() + " " + datarow.getLongmins() + datarow.getLongdir(),
                                datarow.getLatdeg() + " " + datarow.getLatmins() + datarow.getLatdir(),
                                datarow.getAudio().getDescription(),
                                String.valueOf(datarow.getLongdec()),
                                String.valueOf(datarow.getLatdec()), datarow.getAltitude(),
                                datarow.getAudio().getAudioUploadPath().compareToIgnoreCase("") != 0);
                    }

                }



                kml.writeFolderClose();

                kml.writeStartEndFolder(false, formatter.format(datarow.getDate().getTime()), datarow.getLongdeg() + " " + datarow.getLongmins() + datarow.getLongdir(),
                        datarow.getLatdeg() + " " + datarow.getLatmins() + datarow.getLatdir(), String.valueOf(datarow.getLongdec()),
                        String.valueOf(datarow.getLatdec()), datarow.getAltitude());

                kml.writePointsHeader();



                col = filedata.values();
                it = col.iterator();

                while (it.hasNext()) {
                    datarow = (NmeaData) it.next();
                    kml.addPoint(String.valueOf(datarow.getLongdec()), String.valueOf(datarow.getLatdec()), datarow.getAltitude());
                }


                kml.writePointsClose();
                kml.closeDocument();
                filedata.clear();
                
            }
        } catch (Exception e) {
            throw new Exception("Exception: " + e);
        }
    }

    /**
     * A method for taking a separated string (separator can be selected) and outputting
     * an array containing the separated strings  
     * 
	 * @param InputString The String to be split up
	 * @param Seperator The Separator char
	 * @return An array containing the Strings
	 * @throws Exception
	 */
    public String[] StringParser(String InputString, char Seperator) throws Exception {
        try {
            char[] mychar;
            char testchar = ',';
            mychar = InputString.toCharArray();
            String[] returnarray = new String[50];
            int racount = 1;

            for (int i = 0; i < mychar.length; i++) {
                testchar = mychar[i];
                if (testchar == Seperator) {
                    racount++;
                    returnarray[racount] = "";
                } else {
                    if (returnarray[racount] == null) {

                        returnarray[racount] = "" + testchar;
                    } else {
                        returnarray[racount] = returnarray[racount] + testchar;
                    }
                }
            }

            return returnarray;


        } catch (Exception e) {

            throw new Exception("Exception: error parsing line in StringParser " + InputString);
        }

    }
}
